<!doctype html>
<html lang="en">
 <head> 
  <meta charset="UTF-8"> 
  <meta name="description" content="燎火的个人博客"> 
  <meta name="keyword" content="燎火,qq799378666,软件开发,java,c#,js,html,html5,css"> 
  <title>对Java线程池使用的总结</title> 
  <script src="/js/jquery-1.11.1.min.js"></script> 
  <script src="/js/bootstrap-3.3.5/js/bootstrap.js"></script> 
  <link href="/js/bootstrap-3.3.5/css/bootstrap.css" rel="stylesheet"> 
  <script src="/js/base.js"></script> 
  <script src="/js/nav.js"></script> 
  <script src="/js/jquery.toTop.min.js"></script> 
  <link href="/style/article.css" rel="stylesheet"> 
 </head> 
 <body> 
  <div id="main"> 
   <h3 id="title">对Java线程池使用的总结</h3> 
   <div id="content">
    <p style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; margin-bottom: 16px;">&nbsp;最近的项目中，遇到了一些需要频繁使用sql查询，写入文件，可以拆分子任务的情况。为了提高程序吞吐量，我使用了线程池。</p>
    <p style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; margin-bottom: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;一开始，考虑将用户按照数量进行分片，因为在数据库查询中，oracle对where in（）有不得超过1000个查询量的限制，所以考虑将每900个用户分一片，每片为一个task，交给fix线程池处理。</p>
    <p style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; margin-bottom: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;但是每个task又有查询优惠券和查询待评论数两个较大的子任务，这两个子任务需要大量的sql查询，于是又考虑将这两个子任务也封装为task，交给线程池处理。但因为主任务的执行依赖子任务的结果，如果使用同一个线程池，则子任务被提交后，work队列中被执行的任务还是主任务，cpu一直在先提交的主任务上等待Future.get（）的返回，子任务得不到cpu资源去执行，一直在任务队列中等待，这将造成程序的死等待。所以将线程池由fix改为cache，希望提交的任务能得到cpu时间，不会一直在队列中等待。后来这里也引发了问题，将在下一篇文章中说明。</p>
    <p style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; margin-bottom: 16px;">&nbsp; &nbsp;当用户的账单数据被计算出来后，需要调用模板中心生成邮件，还需要将生成的邮件保存到磁盘上，这是两种不同的io密集型任务，一个是在socket上等待，一个是在本地io上等待。考虑到如果继续提交到cache线程池，那么线程池会为每个task生成一个线程，将耗费大量资源，cpu将频繁切换线程，降低了程序的吞吐量。因此新建一个fix线程池，将这些后续任务提交给fix线程池处理，线程池使用固定数量的work去跑，即能在不同阻塞情况下，让程序可以继续运行，也避免了创建大量thread的资源浪费。</p>
    <p style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; margin-bottom: 16px;">&nbsp; &nbsp; 其实最后程序里用了五个线程池，分级使用的原因有以下考虑：</p>
    <p style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; margin-bottom: 16px;">&nbsp; &nbsp; 为了提高程序执行效率，可以将用户先按照语言分类，然后再按照900人一片进行分片，每片任务中，又涉及到两个频繁查询数据库的子任务，每片处理完后，又需要进行网络io生产邮件和磁盘io保存邮件。如果用相同的线程池，则上级任务生产的子任务提交fix线程池后，因为work队列还在被上级任务占用，不同类型的io操作都将在task队列中等待，无法提高系统吞吐量。将下级任务提交到其他线程池后，下级任务就能有立即执行的机会，进行网络io和磁盘读写，提高了运行效率。</p>
    <p><br></p>
   </div> 
  </div>  
 </body>
</html>